#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include "../include/mainoperations.h"
void print_output(int op,char *error);
void create ( char *label1, int size )
{
	int nosblock;
	fd root_dir ;
	FILE *fdi ;
	char last_char =' ';
	int i = 0;
	if(label1==NULL || size == 0)
	{
		printf("createvfs_FAILURE %s\n",ERR_VFS_CREATE_00);
		return;
	}
	int result =access(label1,F_OK);
	if(result==0)	
	{
		printf("createvfs_FAILURE %s\n",ERR_VFS_CREATE_01);	//File already exists
		return;
	}
	// The slash (/) character is not allowed
	if(strstr(label1,"/")!=NULL)
	{
		printf("createvfs_FAILURE %s\n",ERR_VFS_CREATE_03);
		return;
	}
	//check for size range 1 to 1024
	if(size < 1 || size > 1024)
	{
		printf("createvfs_FAILURE %s\n",ERR_VFS_CREATE_04);
		return;
	}
	if(strlen(label1)>30)
	{
		printf("createvfs_FAILURE %s\n",ERR_VFS_CREATE_05); //label exceeds 30 characters
		return;
	}
		
   	while(*label1)
  	{
      		label[i] = *label1;
      		label1++;
      		i++;
    	}
    	label[i] = '\0';

	nosblock = ((size*1024) - 20)/(sizeof(fd) + BLOCK_SIZE + 4);
	size_meta_header = sizeof(int)*5;
	size_of_header_1 = nosblock*sizeof(fd) ;
	size_of_header_2 =  nosblock *4;
	max_fd = nosblock; 
	current_fd_id = 1; 
	no_of_fd = 1 ;
	
	//initialize the root
	
	root_dir.is_dir =1;
	root_dir.fd_id = 1;
	root_dir.size = 0;
	strcpy(root_dir.file_name,"/");
	strcpy(root_dir.path,"/");
		
	if(( fdi = fopen(label,"wb"))== NULL)
	{
		printf("createvfs_FAILURE %s\n",ERR_VFS_CREATE_02);	//File could not be created	
		return;
	}
	else
	{
		fseek(fdi,size*1024, SEEK_SET);
		
		fwrite( &last_char, sizeof(char),1,fdi);
		//store the metaheader data
		fseek(fdi,0, SEEK_SET);
		fwrite( &size_of_header_1, sizeof(int),1,fdi);
		fwrite( &size_of_header_2, sizeof(int),1,fdi);
		fwrite( &max_fd, sizeof(int),1,fdi);
		fwrite( &current_fd_id, sizeof(int),1,fdi);
		fwrite( &no_of_fd, sizeof(int),1,fdi);
		
		// store the root directory info
		fseek(fdi,size_meta_header , SEEK_SET);
		fwrite( &root_dir, sizeof(fd),1,fdi);
		
		// store the free list containg the list of all the block numbers
		//block number starting from 0
		fseek(fdi,size_meta_header + size_of_header_1, SEEK_SET);
		for(i=0; i< max_fd ; i++)
		{
			fwrite( &i, sizeof(int),1,fdi);
		}
		fclose(fdi);
	}
	printf("createvfs_SUCCESS\n");
	/* Call the appropriate function with given arguments and display appropriate output on the screen 
	printf("createvfs_TO_BE_DONE\n");*/
}

void mount ( char *label1 )
{
	if(label1 == NULL)
	{
		printf("mountvfs_FAILURE %s\n",ERR_VFS_MOUNT_00);
		return;
	}
	if(is_mounted == 1)
	{
		printf("mountvfs_FAILURE %s\n",ERR_VFS_MOUNT_03);
		return;
	}
	int i=0;	

	while(*label1)
  	{
     		label[i] = *label1;
      		label1++;
      		i++;
    	}
    	label[i] = '\0';

	fp1 = fopen(label,"r+b");
	i=0;
	int offset;

    	fd *list_of_fd ;
	int result =access(label,F_OK);
	if(result==-1)
	{
		printf("mountvfs_FAILURE %s\n",ERR_VFS_MOUNT_01);//data file not found
		return;
	}
  	if(fp1 == NULL || (access(label,R_OK)==-1))
	{
		printf("mountvfs_FAILURE %s\n",ERR_VFS_MOUNT_02);//cannot read from file
		return;
	}
    	//READ THE GLOBAL VARIABLES
	fseek(fp1,0, SEEK_SET);
	size_meta_header = sizeof(int)*5;
		
	fread( &size_of_header_1, sizeof(int),1,fp1);
	fread( &size_of_header_2, sizeof(int),1,fp1);
	fread( &max_fd, sizeof(int),1,fp1);
	fread( &current_fd_id, sizeof(int),1,fp1);
	fread( &no_of_fd, sizeof(int),1,fp1);
	hash_initialize(h_bucket);
	root = NULL;
	bst_root = NULL;
	
    	fseek(fp1,size_meta_header,SEEK_SET);
    	while(i < no_of_fd)
	{
		list_of_fd = (fd*)malloc(sizeof(fd));
		fread(list_of_fd,sizeof(fd),1,fp1);
		insert_node(&root,list_of_fd);
			
		//ISERTION IN HASH_TABLE
		if(list_of_fd->is_dir == 0)
		{
			hash_insert(h_bucket,list_of_fd);
		    //INSERTION IN BST
			bst_insert (&bst_root,list_of_fd ); 
		}
		i++;
	 }

    	i = 0;             
    	fseek(fp1,size_meta_header+size_of_header_1,SEEK_SET);
   	start=NULL;
    	while(i < (size_of_header_2/4))
	{
		int* off = (int*)malloc(sizeof(int));
        	fread(off,4,1,fp1);
		if(*off == -1)
		  break;
		//LIST_INSERTION_ROUTINE
		void* refData = off;
              
		start = list_insert_head(start,refData);
		i++;
	}
	is_mounted = 1;
	printf("mountvfs_SUCCESS\n");
	/* Call the appropriate function with given arguments and display appropriate output on the screen 
	printf("mountvfs_TO_BE_DONE\n");*/
}

void unmount ( char *label1 )
{
	if(label1 == NULL || strcmp(label1," ")==0)
	{
		printf("unmountvfs_FAILURE %s\n",ERR_VFS_UNMOUNT_00);
		return;
	}
	int result =access(label,F_OK);
	if(result==-1)
	{
		printf("unmountvfs_FAILURE %s\n",ERR_VFS_UNMOUNT_01);//data file not found
		return;
	}
	if(is_mounted == 0)
	{
		printf("unmountvfs_FAILURE %s\n",ERR_VFS_UNMOUNT_03);
		return;
	}

  	if(fp1 == NULL || (access(label,W_OK)==-1))
	{
		printf("unmountvfs_FAILURE %s\n",ERR_VFS_UNMOUNT_02);//cannot write to file
		return;
	}
	int dq;
    	int res;
	int blkcount;
	int no_of_blks;
	l_node* temp;
	fflush(stdin);

	//STORE CURRENT_DESCRIPTOR
				
	fseek(fp1,0, SEEK_SET);
	fwrite( &size_of_header_1, sizeof(int),1,fp1);
	fwrite( &size_of_header_2, sizeof(int),1,fp1);
	fwrite( &max_fd, sizeof(int),1,fp1);
	fwrite( &current_fd_id, sizeof(int),1,fp1);
	fwrite( &no_of_fd, sizeof(int),1,fp1);		

	//STORE N-ARRAY TREE
	fseek(fp1,20,SEEK_SET);
	res = savetree( root,fp1,&save_node );
	 free_recur(&root);
	//STORE THE FREE_LIST
	fseek(fp1,size_meta_header+size_of_header_1,SEEK_SET); 

	temp = start;
	blkcount = 0;
	no_of_blks = size_of_header_2/4;
	while(temp!=NULL)
	{
		int* off = (int*)temp->data;
		fwrite(&off,sizeof(int),1,fp1);
		temp = temp->next;
		blkcount++;
		
	}
	if(blkcount < no_of_blks)
	{
		while(blkcount < no_of_blks)
		{
		    int* off = (int*)malloc(sizeof(int));
			*off = -1;
			fwrite(off,4,1,fp1);
			blkcount++;
	    	}
	}
			  
	fclose(fp1); 
	is_mounted = 0; 
	printf("unmountvfs_SUCCESS\n");
	/* Call the appropriate function with given arguments and display appropriate output on the screen 
	printf("unmountvfs_TO_BE_DONE\n");*/
}
int savetree( t_node *subtree, FILE *fileDes, int (*save_node) ( FILE *fileDes, fd *data ) )
{
	int result = 0;
			 
	/* Save current node using callback function */
	if( subtree == NULL)
	{
		return 0;
	}
	else
	{
		if(subtree->is_deleted == 0)
		{
			result = save_node( fileDes, subtree->data );
			if( result != 0 )
			{
				fprintf(stderr, "savetree: Error while saving..%d\n", subtree->data->fd_id);
				return result;
			}
		}
	}
	if( subtree->left_child!= NULL )
	{
		result = savetree( subtree->left_child, fileDes, save_node );
		if( result != 0 )
		{
			fprintf(stderr, "savetree: Error while saving ... %d\n", subtree->data->fd_id);
			return result;
		}
	}

	if( subtree->right_siblings != NULL )
	{
		result = savetree( subtree->right_siblings, fileDes, save_node );
		if( result != 0 )
		{
			fprintf(stderr, "savetree: Error while saving .. %d\n", subtree->data->fd_id);
			return result;
		}
	}
	return result;
}

int save_node( FILE *fileDes, fd *data )
{
	
	fwrite(data, sizeof(fd), 1, fileDes);
	
	return 0;
}

void free_recur(t_node **root)
{
	if((*root) == NULL)
		return;
	if((*root)->left_child!=NULL)
		free_recur(&(*root)->left_child);
	if((*root)->right_siblings!=NULL)
		free_recur(&(*root)->right_siblings);
	free((*root));
	return;
} 
void dmake ( char *path, char *dirname )//path - P1, dirname-P2
{
	if(path == NULL || dirname == NULL || !strcmp(dirname," "))
	{
		printf("makedir_FAILURE %s\n",ERR_VFS_MAKEDIR_00);
		return;
	}
	if(is_mounted == 0)
	{
		printf("makedir_FAILURE %s\n",ERR_VFS_MAKEDIR_05);
		return;
	}
	
	int result,nop;
	char **token;
	int i,k;
	char fullp[] = "/";
	int len1,len2;
	char path2[]="/";
	int flag=0;
	// The slash (/) character is not allowed
	if(strstr(dirname,"/")!=NULL)
	{
		printf("makedir_FAILURE %s\n",ERR_VFS_MAKEDIR_02);
		return;
	}
	if(strcmp(path,"/")!=0) 
	{
		path=slash_truncate(path);
		//("path:%s\n",path);
	}
	l_node *start1 = start;
	//Free List empty	
	if((max_fd == current_fd_id)|| (start1 == NULL))
	{
		printf("makedir_FAILURE %s\n",ERR_VFS_MAKEDIR_01);//file system full
		return;
	}
	nop = get_tokens(&token,path,'/');
	if(strcmp(path,"/")==0) 
		nop--;
	i = 1;//printf("herenop:%d",nop);
	for(i=1 ; i<nop ; i++)
	{
		t_node *node = (t_node *)malloc(sizeof(t_node));
		strcpy(path2,fullp);
		strcat(fullp,token[i]);
		node  = returnnode(root,fullp);	
		if(node == NULL)
		{	
			break; 
		}
		strcat(fullp,"/");

	}
	
	while(i<nop)
	{
		//Prepare the fd
		fd *data = (fd*)malloc(sizeof(fd));
		data->is_dir = 1;
		data->fd_id = current_fd_id;
		data->size= 0;
		strcpy(data->file_name,token[i]);
		strcpy(data->path,path2);


		//Insert into N-ary tree
	
		result =  insert_node(&root,data);
	
		//Is it a Duplicate?	
		if(result == -1)
		{
		printf("makedir_FAILURE %s\n",ERR_VFS_MAKEDIR_03);//directory already exists
		return;
		}

		//Increment the Globals
		current_fd_id ++;
		no_of_fd ++;
		if((max_fd == current_fd_id)|| (start1 == NULL))
		{
			printf("makedir_FAILURE %s\n",ERR_VFS_MAKEDIR_01);//file system full
			return;
		}
		if(strcmp(path2,"/")==0)
		strcat(path2,token[i]); 
		else
		{
			strcat(path2,"/"); strcat(path2,token[i]); 
		}
		i++;
	}
		
	//Prepare the fd
	fd *data = (fd*)malloc(sizeof(fd));
	data->is_dir = 1;
	data->fd_id = current_fd_id;;
	data->size= 0;
	strcpy(data->file_name,dirname);
	strcpy(data->path,path);
	//Insert into N-ary tree
	result =  insert_node(&root,data);
	
	//Is it a Duplicate?	
	if(result == -1)
	{
		printf("makedir_FAILURE %s\n",ERR_VFS_MAKEDIR_03);//directory already exists
		return;
	}

	//Increment the Globals
	current_fd_id ++;
	no_of_fd ++;
	printf("makedir_SUCCESS\n");

	/* Call the appropriate function with given arguments and display appropriate output on the screen 
	printf("makedir_TO_BE_DONE\n");*/
}

void ddelete ( char *path )
{	
	if(path==NULL || strcmp(path," ")==0)
	{
		printf("deletedir_FAILURE %s\n",ERR_VFS_DELETEDIR_00);
		return;
	}
	if(is_mounted == 0)
	{
		printf("deletedir_FAILURE %s\n",ERR_VFS_DELETEDIR_04);
		return;
	}
	else
	{
		t_node * node = (t_node *)malloc(sizeof(t_node));
		
		node  = returnnode(root,path); 
		//printf("node:%s\n",node->data->file_name);
//printf("here");
//exit(0);
		if(node==NULL)
		{
			printf("deletedir_FAILURE %s\n",ERR_VFS_DELETEDIR_01);//cannot find the specified dir
			return 0;
		}
		else if(strcmp(node->data->file_name,"/")==0)
		{
			printf("deletedir_FAILURE %s\n",ERR_VFS_DELETEDIR_01);//cannot find the specified dir
			return 0;
		}
		else if((node->left_child==NULL) && (node->data->is_dir==1))
		{
			no_of_fd--;
			remove_a_node(node,&root);
		}
		else
		{
			printf("deletedir_FAILURE %s\n",ERR_VFS_DELETEDIR_02);//directory not empty
		}
	}

	/* Call the appropriate function with given arguments and display appropriate output on the screen 
	printf("deletedir_TO_BE_DONE\n");*/
}

void dmove ( char *P1, char *P2 )
{
	if(P1 == NULL || P2 == NULL)
	{
		printf("movedir_FAILURE %s\n",ERR_VFS_MOVEDIR_00);
		return;
	}
	if(is_mounted == 0)
	{
		printf("movedir_FAILURE %s\n",ERR_VFS_MOVEDIR_08);
		return;
	}
	printf("movedir_SUCCESS\n");

	/* Call the appropriate function with given arguments and display appropriate output on the screen */
	printf("movedir_TO_BE_DONE\n");
}

void dlist ( char *P1, int P2, char *P3 ) //P1=sourcedir P2=flag P3=destfile
{
	if(P1==NULL || isdigit(P2) ||P3==NULL)
	{
		printf("listdir_FAILURE %s\n",ERR_VFS_LISTDIR_00);
		return;
	}
	if(is_mounted == 0)
	{
		printf("listdir_FAILURE %s\n",ERR_VFS_LISTDIR_03);
		return;
	}
	if(P2!=1 && P2!=0)
	{
		printf("listdir_FAILURE %s\n",ERR_VFS_LISTDIR_02);
		return 0;
	}

	FILE *fp2;
	fp2=fopen(P3,"wb+");                   
	if(fp2==NULL)
	{
		printf("listdir_FAILURE %s\n",ERR_VFS_LISTDIR_04);
		return 0;
	}
	else
	{
		t_node * node = (t_node *)malloc(sizeof(t_node));
		node  = returnnode(root,P1); 
		if(node==NULL)
		{
			printf("listdir_FAILURE %s\n",ERR_VFS_LISTDIR_01);
			return 0;
		}
		if(node->is_deleted==FALSE)
		{
			if(P2==0)
			{	
				Nonrecursive_Print(node,fp2);
			}
			else 
			{	
				Recursive_Print(node,fp2);
			}
		}
		else
		{
			printf(ERR_VFS_LISTDIR_01);
		}
	}
	printf("listdir_SUCCESS\n");
	/* Call the appropriate function with given arguments and display appropriate output on the screen 
	printf("listdir_TO_BE_DONE\n");*/
}

void fadd ( char *P1, char *P2, char *P3 )//P3=data p2=filename p1=path
{
	//1. Perform necessary error checks.
	if(P1 == NULL || P2== NULL || P3==NULL)
	{
		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_00);
		return;	
	}
	
	if(is_mounted == 0)
	{
		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_07);
		return;
	}
	// The slash (/) character is not allowed
	if(strstr(P2,"/")!=NULL)
	{
		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_02);//invalid character in file name
		return;
	}
	P1=slash_truncate(P1);

	int length = 0;
	//int blocks= 0;
	int free_blocks;
	char ch;
    	FILE *fp2;
	int result,result1,result2;

	//2. Calculate the number of blocks required to store the file.   
  	fp2=fopen(P3,"rb");
  	if(fp2==NULL || (access(P3,R_OK)==-1))
  	{
		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_08);
    		return;
  	}
  	fseek(fp2, 0L, SEEK_END);
    	length=ftell(fp2);
    	if(length>1024)
    	{
    		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_06);//file too large
    		return;
    	}
     
    	fseek(fp2, 0L, SEEK_SET);
	//3. Retrieve free blocks from the free list.
	
	l_node *start1 = start;
	//Free List empty	
	if(start1 == NULL)
	{
		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_04);//file system full
		return;	
	}
	//Prepare a fd * and error check for duplication
	fd *temp = (fd*)malloc(sizeof(fd));
	temp->is_dir = 0;
	temp->fd_id = current_fd_id;
	temp->size=length;
	strcpy(temp->file_name,P2);
	strcpy(temp->path,P1);

	temp->blocks[0]=*(int *)start1->data;
	
	//Mark the end
	temp->blocks[1] = -1;

	//Is it a duplicate?
	result =  insert_node(&root,temp);
	result1 = bst_insert (&bst_root, temp);
    	result2  = hash_insert(h_bucket, temp);
	if(result == -1 || result1==1 || result2==-1)
	{
		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_03);//file already exists
		return;
	}

	//4. Seek to the specified offsets and write the data.
	
	//fp2 = fopen(label,"rb+");
	fseek(fp1, 20 + size_of_header_1 + size_of_header_2+(temp->blocks[0]* BLOCK_SIZE), SEEK_SET);
	
  	if(fp1 == NULL || (access(label,W_OK)==-1))
	{
		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_05);//cannot write to file
		return;
	}
	//Write the data into file

	while((ch=getc(fp2))!=EOF)
      		putc(ch,fp1);		
	
	fclose(fp2);
	//fclose(fp2);
	start = list_delete_head(start);
	//6. update global variables.
	current_fd_id ++;
	no_of_fd ++;
	printf("addfile_SUCCESS\n");
	//return 0;
	//Call the appropriate function with given arguments and display appropriate output on the screen 
	//printf("addfile_TO_BE_DONE\n");
}

void flist ( char *P1, char *P2)
{
	if(P1 == NULL || P2 == NULL)
	{
		printf("listfile_FAILURE %s\n",ERR_VFS_LISTFILE_00);
		return;	
	}
		
	if(is_mounted == 0)
	{
		printf("listfile_FAILURE %s\n",ERR_VFS_LISTFILE_04);
		return;
	}
	
	int j;
	char ch;
	FILE *fp2;
	P1=slash_truncate(P1);
	//1. Search for the file.
	b_node * node = (b_node *)malloc(sizeof(b_node));
	node  = bst_search(bst_root,P1);
	//File not found	
	if(node == NULL)
	{
		printf("listfile_FAILURE %s\n",ERR_VFS_LISTFILE_01);
		return;
	}
	//int nop=get_tokens(&token,path,'.');
	char *sub1;
	int len=strlen(P1);
	//printf("%d",len);
	//printf("%c\n",P1[len-4]);
	sub1=substring(P1,len-3,len);	//substring( string, position, length);
	//printf("sub1:%s",sub1);
	if(strcmp(sub1,".txt")!=0)
	{
		printf("listfile_FAILURE %s\n",ERR_VFS_LISTFILE_02);//Not a text file
		return;
	}
	fd *temp = (fd*)malloc(sizeof(fd));
	temp = node->file_desc;
	/*printf("hed1:%d\n",size_of_header_1);
	printf("hed2:%d\n",size_of_header_2);
	printf("fiename:%s",temp->file_name);
	printf("path:%s",temp->path);
	printf("isdir:%d",temp->is_dir);
	printf("fd_id:%d",temp->fd_id);
	printf("size:%d",temp->size);
	//3. Seek to corresponding offsets and read the data.
	*///printf("temp lock0:%d",temp->blocks[0]);
	//fp1 = fopen(label,"rb");	
	fp2 = fopen(P2,"w");
	//if(fp1==NULL || fp2==NULL)
	if(fp2==NULL)
	{
		printf("listfile_FAILURE %s\n",ERR_VFS_LISTFILE_03);
		return;
	}
	fseek(fp1, 20 + size_of_header_1 + size_of_header_2+(BLOCK_SIZE*temp->blocks[0]), SEEK_SET);
	//printf("\nadd of fp1 %p %d",fp1,BLOCK_SIZE*temp->blocks[0]);
	for(j=0; j<temp->size; j++)
	{
		fread(&ch, sizeof(char), 1, fp1);//printf("%c\n",ch);
		putc(ch,fp2);
	}	
	//fclose(fp1);
	fclose(fp2);
	printf("listfile_SUCCESS\n");
	//return 0;
	// Call the appropriate function with given arguments and display appropriate output on the screen 
	//printf("listfile_TO_BE_DONE\n");
}

void fupdate ( char *P1, char *P2 )
{
	if(P1 == NULL || P2== NULL )
	{
		printf("updatefile_FAILURE %s\n",ERR_VFS_UPDATEFILE_00);
                return;
	}

	if(is_mounted == 0)
	{
		printf("updatefile_FAILURE %s\n",ERR_VFS_UPDATEFILE_04);
		return;
	}
	char ch;
        FILE *fp2;
        int length = 0;
	P1=slash_truncate(P1);
        b_node * node = (b_node *)malloc(sizeof(b_node));
    	//1. Search for the file.
        node  = bst_search(bst_root,P1);

        //File not found       
        if(node == NULL)
	{
		printf("updatefile_FAILURE %s\n",ERR_VFS_UPDATEFILE_01);
                return;
	}
        fd *temp = (fd*)malloc(sizeof(fd));

        fp2=fopen(P2,"rb");
        if(fp2==NULL || (access(P2,R_OK)==-1))
        {
        	printf("updatefile_FAILURE %s\n",ERR_VFS_UPDATEFILE_02);
       		return;
        }
        fseek(fp2, 0L, SEEK_END);
	length=ftell(fp2);
    	if(length>1024)
    	{
        	printf("updatefile_FAILURE %s\n",ERR_VFS_UPDATEFILE_03);
        	return;
    	}
    
    	fseek(fp2, 0L, SEEK_SET);
        temp = node->file_desc;
        temp->size=length;

	//fp2 = fopen(label,"rb+");
        fseek(fp1, 20 + size_of_header_1 + size_of_header_2+(temp->blocks[0] * BLOCK_SIZE), SEEK_SET);

	//Write the data into file
        while((ch=getc(fp2))!=EOF)
                 putc(ch,fp1);              
        fclose(fp2);
	printf("updatefile_SUCCESS\n");
	/* Call the appropriate function with given arguments and display appropriate output on the screen */
	//printf("updatefile_TO_BE_DONE\n");
}

void fremove ( char *P1)
{
	if(P1 == NULL)
	{
		printf("removefile_FAILURE %s\n",ERR_VFS_REMOVEFILE_00);
		return;
	}
	if(is_mounted == 0)
	{
		printf("removefile_FAILURE %s\n",ERR_VFS_REMOVEFILE_02);
		return;
	}
	int  result,result1,result2;
	P1=slash_truncate(P1);
	//1. Search the file in BST.
	b_node * node;
	node  = bst_search(bst_root,P1);

	//File not found	
	if(node == NULL)
	{
		printf("removefile_FAILURE %s\n",ERR_VFS_REMOVEFILE_01);		
		return;
	}

	fd *temp = (fd*)malloc(sizeof(fd));
	temp = node->file_desc;
	//printf("deldtednode:%d",(int *)temp->blocks[0]);
	start = list_insert_head(start,(int *)temp->blocks[0]);

	//4. Remove the file from N-ary Tree, Hash and BST.
	result = bst_delete(&bst_root,P1);
	result1 = hash_delete(h_bucket, temp->path,temp->file_name);
	result2 = delete_node(&root,P1);
	if(result==0 && result1==0 && result2==0)
	{	
		printf("removefile_SUCCESS\n");
	//	printf("Removed file successfully...\n");
	}
	//5. Update the global variables.
	current_fd_id --;
	no_of_fd --;
	
	//return 0;
	/* Call the appropriate function with given arguments and display appropriate output on the screen 
	printf("removefile_TO_BE_DONE\n");*/
}

void fmove ( char *P1, char *P2 )
{
	if(P1== NULL || P2 == NULL)
	{
		printf("movefile_FAILURE %s\n",ERR_VFS_MOVEFILE_00);
		return;
	}	
	if(is_mounted == 0)
	{
		printf("movefile_FAILURE %s\n",ERR_VFS_MOVEFILE_06);
		return;
	}
	if(access(P1,F_OK)==-1)
	{
		printf("movefile_FAILURE %s\n",ERR_VFS_MOVEFILE_01);//cannot find source file
		return;
	}
	if(access(P2,F_OK)==-1)
	{
		printf("movefile_FAILURE %s\n",ERR_VFS_MOVEFILE_02);//cannot find destination file
		return;
	}

	copyfile(P1,P2);
	removefile(P1);
	printf("movefile_SUCCESS\n");
	/* Call the appropriate function with given arguments and display appropriate output on the screen */
	//printf("movefile_TO_BE_DONE\n");
}

void fcopy ( char *P1, char *P2 )
{
	if(P1 == NULL || P2== NULL)
	{
		printf("copyfile_FAILURE %s\n",ERR_VFS_COPYFILE_00);
		return;
	}	
	if(is_mounted == 0)
	{
		printf("copyfile_FAILURE %s\n",ERR_VFS_COPYFILE_05);
		return;
	}

	FILE *fp2;
	int j,result,result1,result2;
	char ch;
	char *arr;
	l_node *start1 = start;
	//Free list empty	
	if(start1 == NULL)
	{
		printf("copyfile_FAILURE %s\n",ERR_VFS_COPYFILE_04); //file system full
		return;
	}
	b_node * node = (b_node *)malloc(sizeof(b_node));
	node  = bst_search(bst_root,P1);
   
	//File not found	
	if(node == NULL)
	{
		printf("copyfile_FAILURE %s\n",ERR_VFS_COPYFILE_01);
		return;		
	}
	if(access(P2,F_OK)==-1)
	{
		printf("copyfile_FAILURE %s\n",ERR_VFS_COPYFILE_02);//cannot find destination file path
		return;
	}		
	fd *temp = (fd*)malloc(sizeof(fd));
	temp = node->file_desc;
	if(temp->is_dir == 1)
	{
		printf("copyfile_FAILURE %s\n",ERR_VFS_COPYFILE_03);
		return;
	}
	/*if(no_of_fd == max_fd)
	{
		printf(ERR_VFS_COPYFILE_04);
		printf("\n");
		return;
	}*/
	fd *newfd = (fd*)malloc(sizeof(fd));
	newfd->is_dir = 0;
	newfd->fd_id = current_fd_id;
	newfd->size=temp->size;
	arr=(char *)malloc(sizeof(char)*temp->size);
	strcpy(newfd->file_name,temp->file_name);
	strcpy(newfd->path,P2); 
	newfd->blocks[0]= *(int *)start1->data;

	//Mark the end
	newfd->blocks[1]=-1; 
	
	result =  insert_node(&root,newfd);
	result1 = bst_insert (&bst_root,newfd);
   	result2  = hash_insert(h_bucket,newfd);
	if(result == -1 || result1==1 || result2==-1)
	{
//		printf("copyfile_FAILURE %s\n");
		return 1;
	}

	fseek(fp1, 20 + size_of_header_1 + size_of_header_2+(temp->blocks[0]*BLOCK_SIZE), SEEK_SET);
	for(j=0; j<temp->size; j++)
	{
		fread(&ch, sizeof(char), 1, fp1);
		arr[j]=ch;
	}	

	fseek(fp1, 20 + size_of_header_1 + size_of_header_2+(newfd->blocks[0]*BLOCK_SIZE), SEEK_SET);
	for(j=0; j<temp->size; j++)
		putc(arr[j],fp1);

	//Free lIst now pointing to nex free block
	start = list_delete_head(start);
	current_fd_id ++;
	no_of_fd ++;
	printf("copyfile_SUCCESS\n");
	/* Call the appropriate function with given arguments and display appropriate output on the screen */
	//printf("copyfile_TO_BE_DONE\n");

}

void fexport ( char *P1, char *P2 )//P1=vfs_file_path and P2=hard_disk_path
{
	if(P1 == NULL || P2 == NULL)
	{
		printf("exportfile_FAILURE %s\n",ERR_VFS_EXPORTFILE_00);
		printf("\n");
		return;
	}
	if(is_mounted == 0)
	{
		printf("exportfile_FAILURE %s\n",ERR_VFS_EXPORTFILE_04);
		return;
	}	

	int j;
	char ch;

	//1. Search for the file.
	b_node * node = (b_node *)malloc(sizeof(b_node));
	node  = bst_search(bst_root,P1);

	//File not found	
	if(node == NULL)
	{
		printf("exportfile_FAILURE %s\n",ERR_VFS_EXPORTFILE_01);
		//printf("\n");
		return;
	}

	fd *temp = (fd*)malloc(sizeof(fd));
	temp = node->file_desc;

	if(temp->is_dir == 1)
	{
		printf("exportfile_FAILURE %s\n",ERR_VFS_EXPORTFILE_03);
		//printf("\n");		
		return;
	}
	
	//Concatenate file path with file name	
	strcat(P2,"/");		
	strcat(P2,temp->file_name);
	//printf("hard_disk_path:%s\n",hard_disk_path);
	
	//2. Seek to corresponding offsets and read the data.

	//Write to another file
	FILE *fp2;//fp=fp2
	fp2 = fopen(P2,"wb");
	if(fp2==NULL)
	{
		printf("exportfile_FAILURE %s\n",ERR_VFS_EXPORTFILE_02);//Error in opening file
		//printf("\n");
		return;
	}
	
	fseek(fp1, 20 + size_of_header_1 + size_of_header_2+(1024*temp->blocks[0]), SEEK_SET);	
	for(j=0; j<temp->size; j++)
	{
		fread(&ch, sizeof(char), 1, fp1);
		putc(ch,fp2);
	}	
	fclose(fp2);
	printf("exportfile_SUCCESS\n");
	/* Call the appropriate function with given arguments and display appropriate output on the screen */
	//printf("exportfile_TO_BE_DONE\n");
}
void fsearch ( char *P1, char *P2 )
{
	if(P1==NULL || P2==NULL)
	{
		printf("searchfile_FAILURE %s\n",ERR_VFS_SEARCHFILE_00);
		return;
	}
	if(is_mounted == 0)
	{
		printf("searchfile_FAILURE %s\n",ERR_VFS_SEARCHFILE_02);
		return;
	}
	FILE *fp2;
	fp2=fopen(P2,"w");
	if(fp2==NULL)
	{
		printf("searchfile_FAILURE %s\n",ERR_VFS_SEARCHFILE_01);
		return 0;
	}
	int len=strlen(P1);
	int count=hash_find(h_bucket, P1, fp2,len);
	printf("searchfile_SUCCESS %d\n",count);
	return;
	/* Call the appropriate function with given arguments and display appropriate output on the screen */
	//printf("searchfile_TO_BE_DONE\n");
}
char * slash_truncate(char *P1)
{
	int len=strlen(P1);
	len=len-1;
	if(P1[len]=='/')
	{
		P1[len]='\0';
	}
	return P1;
}
char *substring(char *string, int position, int length) 
{
   char *pointer;
   int c;
 
   pointer = malloc(length+1);
 
   if (pointer == NULL)
   {
      printf("Unable to allocate memory.\n");
      exit(EXIT_FAILURE);
   }
 
   for (c = 0 ; c < position -1 ; c++) 
      string++; 
 
   for (c = 0 ; c < length ; c++)
   {
      *(pointer+c) = *string;      
      string++;   
   }
 
   *(pointer+c) = '\0';
 
   return pointer;
}
